package com.daJiao.aspect;

import com.alibaba.fastjson.JSONObject;
import com.daJiao.constants.Constants;
import com.daJiao.domain.WrapMapper;
import com.daJiao.domain.Wrapper;
import com.daJiao.exception.BusinessException;
import com.daJiao.properties.AlarmProperties;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.core.env.Environment;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.*;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import java.util.Map;
import java.util.Objects;


/**
 * <p>Title:	  GlobalExceptionHandler. </p>
 * <p>Description 添加全局异常处理流程，根据需要设置需要处理的异常 </p>
 * <p>Company:    医百科技有限公司 </p>
 *
 * @Author <a href="xinglinglove1029@163.com"/>杨文生</a>
 * @CreateDate 2017 /8/18 13:47
 */
@RestControllerAdvice
@Slf4j
public class ResponseResultBodyAdvice {

    @Resource
    private AlarmProperties alarmProperties;

    @Resource
    private Environment environment;


    @ExceptionHandler(value = Exception.class)
    @ResponseStatus(HttpStatus.OK)
    public Wrapper<?> globalException(Exception exception) {
        log.error("服务器内部异常:{},{}", exception.getMessage(), exception);
        sendAlarmMessage(exception);
        return WrapMapper.wrap(Wrapper.ERROR_CODE, Wrapper.ERROR_MESSAGE);
    }

    /**
     * Method argument not valid handler object.
     *
     * @param exception the exception
     * @return the object
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.OK)
    public Wrapper<?> handleMethodArgumentNotValidException(MethodArgumentNotValidException exception) {
        log.error(exception.getMessage(), exception);
        return WrapMapper.wrap(Wrapper.ERROR_CODE, Objects.requireNonNull(exception.getBindingResult().getFieldError()).getDefaultMessage());
    }


    /**
     * ValidationException
     */
    @ExceptionHandler(ValidationException.class)
    @ResponseStatus(HttpStatus.OK)
    public Wrapper<?> handleValidationException(ValidationException exception) {
        log.error(exception.getMessage(), exception);
        return WrapMapper.wrap(Wrapper.ERROR_CODE, exception.getMessage());
    }

    /**
     * ConstraintViolationException
     */
    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseStatus(HttpStatus.OK)
    public Wrapper<?> handleConstraintViolationException(ConstraintViolationException exception) {
        log.error(exception.getMessage(), exception);
        return WrapMapper.wrap(Wrapper.ERROR_CODE, exception.getMessage());
    }


    @ExceptionHandler(DuplicateKeyException.class)
    @ResponseStatus(HttpStatus.OK)
    public Wrapper<?> handleDuplicateKeyException(DuplicateKeyException exception) {
        log.error(exception.getMessage(), exception);
        return WrapMapper.wrap(Wrapper.ERROR_CODE, "数据重复，请检查后提交");
    }


    /**
     * Illegal argument exception wrapper.
     *
     * @param exception the exception
     * @return the wrapper
     */
    @ExceptionHandler(IllegalArgumentException.class)
    @ResponseStatus(HttpStatus.OK)
    public Wrapper<?> illegalArgumentException(IllegalArgumentException exception) {
        log.error("参数非法异常:{},{}", exception.getMessage(), exception);
        return WrapMapper.wrap(Wrapper.ERROR_CODE, exception.getMessage());
    }

    /**
     * Not fount wrapper.
     *
     * @param exception the exception
     * @return the wrapper
     */
    @ExceptionHandler(BusinessException.class)
    @ResponseStatus(HttpStatus.OK)
    public Wrapper<?> businessException(BusinessException exception) {
        log.error("业务异常:{},{}", exception.getMessage(), exception);
        sendAlarmMessage(exception);
        return WrapMapper.wrap(exception.getCode(), exception.getMessage(), exception.getData());
    }


    @ExceptionHandler(WxErrorException.class)
    @ResponseStatus(HttpStatus.OK)
    public Wrapper<?> wxErrorException(WxErrorException exception) {
        log.error("业务异常:{},{}", exception.getMessage(), exception);
        return WrapMapper.wrap(Wrapper.ERROR_CODE, exception.getMessage());
    }

    @ExceptionHandler(RuntimeException.class)
    @ResponseStatus(HttpStatus.OK)
    public Wrapper<?> runtimeException(RuntimeException exception) {
        log.error("服务器运行异常:{},{}", exception.getMessage(), exception);
        sendAlarmMessage(exception);
        return WrapMapper.wrap(Wrapper.ERROR_CODE, exception.getMessage());
    }

    /**
     * 程序异常发送告警消息
     *
     * @param throwable Throwable
     */
    private void sendAlarmMessage(Throwable throwable) {
        try {
            StringBuilder content = new StringBuilder();
            content.append("项目名称：").append(environment.getProperty("spring.application.name")).append("\n");
            content.append("所属环境：").append(environment.getProperty("spring.profiles.active")).append("\n");
            content.append("异常内容：").append(ExceptionUtils.getStackTrace(throwable));
            JSONObject param = new JSONObject();
            if (Constants.ALARM_TYPE_SLACK.equals(alarmProperties.getAlarmType())) {
                param.put("text", content.toString());
                param.put("channel", alarmProperties.getChannel());
                param.put("username", alarmProperties.getUsername());
                param.put("icon_emoji", alarmProperties.getEmoji());
            } else {
                param.put("msgtype", "text");
                Map<String, Object> textParam = Maps.newHashMap();
                textParam.put("content", content.toString());
                param.put("text", textParam);
            }
            RestTemplate restTemplate = new RestTemplate();
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            HttpEntity<String> request = new HttpEntity<>(param.toJSONString(), headers);
            restTemplate.exchange(alarmProperties.getAlarmUrl(), HttpMethod.POST, request, String.class).getBody();
        } catch (RestClientException e) {
            log.error("推送告警信息异常：{}", e.getMessage());
        }
    }

}